package org.jheuristics.ga.operators.selectors;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;

import org.epanetgrid.otimizacao.log.AGLogger;
import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.DefaultPopulation;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.Population;
import org.jheuristics.util.RandomGenerator;


/**
 * TODO
 * 
 * @author Marcell Manfrin, marcell at ourgrid.org, 2005
 */
public class DefaultTournamentSelectionVinicius extends AbstractTournamentSelection {
	private int tournamentSize;
	private int numOfTournaments;

	private AGLogger logger = AGLogger.getInstance();
	
	/**
	 * TODO
	 */
	public DefaultTournamentSelectionVinicius() {
		super();
		setTournamentSize(2);
		setNumOfTournaments(-1);
	}

	/**
	 * TODO
	 *
	 * @param comparator
	 */
	public DefaultTournamentSelectionVinicius(Comparator comparator) {
		super(comparator);
	}

	/**
	 * TODO
	 * 
	 * @param tournamentSize
	 */
	public DefaultTournamentSelectionVinicius(int tournamentSize, int numOfTournaments) {
		setTournamentSize(tournamentSize);
		setNumOfTournaments(numOfTournaments);
	}

	/**
	 * TODO
	 * 
	 * @param tournamentSize
	 */
	public DefaultTournamentSelectionVinicius(Comparator comparator, int tournamentSize) {
		setComparator(comparator);
		setTournamentSize(tournamentSize);
	}

	/**
	 * TODO
	 * 
	 * @param individuals
	 * @param status
	 * @param config
	 * @return
	 * @see org.jheuristics.ga.operators.selectors.AbstractTournamentSelection#select(org.jheuristics.Individual[],
	 * org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected Individual select(Individual[] individuals, GAStatus status, GAConfig config) {
		RandomGenerator random = config.getRandomGenerator();
		Individual result = individuals[random.nextInt(individuals.length)];
		List<Individual> participantes = new LinkedList<Individual>();
		participantes.add(result);
		for (int i = 0; i < getTournamentSize() - 1; i++) {
			Individual selected = individuals[random.nextInt(individuals.length)];
			participantes.add(selected);
			if (null == getComparator()) {
				if (result.compareTo(selected) < 0) {
					result = selected;
				}
			} else {
				if (getComparator().compare(result, selected) < 0) {
					result = selected;
				}
			}
		}
		
		
		StringBuffer buf = new StringBuffer();
		buf.append("\n");
		buf.append("Indivíduos selecionados para torneio: ");
		buf.append("\n");
		for (Individual individual : participantes) {
			buf.append(OtimizacaoUtil.format(individual));
			buf.append("\n");
		}
		
		buf.append("Indivíduo Campeão: \n");
		buf.append(OtimizacaoUtil.format(result));
		buf.append("\n");
		logger.debug(buf);
		return result;
	}

	/**
	 * TODO
	 * 
	 * @return
	 */
	public int getTournamentSize() {
		return tournamentSize;
	}

	/**
	 * TODO
	 * 
	 * @param tournamentSize
	 */
	public void setTournamentSize(int tournamentSize) {
		if (0 >= tournamentSize) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}
		this.tournamentSize = tournamentSize;
	}
	
	/**
	 * @param numOfTournaments
	 */
	public void setNumOfTournaments(int numOfTournaments) {
		if (0 >= numOfTournaments) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}
		this.numOfTournaments = numOfTournaments;
	}

	@Override
	public Individual[] select(Population population, int howMany, GAStatus status, GAConfig config) {
		
		logger.debug("******** Iniciando operador de sele��o*****************");
		logger.debug("Quantidade de torneios: "+ (this.getNumOfTournaments() == -1?
				population.size() / 2:getNumOfTournaments()));
		logger.debug("Tamanho dos torneios: "+ getTournamentSize());
		
		if (null == population) {
			// TODO: ERROR MSG
			throw new NullPointerException();
        }
        if (null == config) {
			// TODO: ERROR MSG
			throw new NullPointerException();
        }
        if (0 == population.size()) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
        }
        Individual[] individuals = population.toIndividualArray();
        Population result = new DefaultPopulation();
        
        
        
        
        if(this.getNumOfTournaments() == -1) {
        	for (int i = 0; i < individuals.length / 2; i++) {
        		result.addIndividual(select(individuals, status, config));
        	}
        }else {
        	for (int i = 0; i < getNumOfTournaments(); i++) {
        		result.addIndividual(select(individuals, status, config));
        	}
        }
        
        StringBuffer buffer = new StringBuffer("População gerada pelo torneio: ");
        buffer.append(result.size());
        buffer.append("\n");
        buffer.append(OtimizacaoUtil.format(result));
//        for (int i = 0; i < result.size(); i ++) {
//			buffer.append(result.getIndividual(i));
//			buffer.append("\n");
//		}
        
        logger.debug(buffer);
        
        logger.debug("******** Iniciando operadores de reprodução*****************");
        
		return result.toIndividualArray();
	}

	public int getNumOfTournaments() {
		return numOfTournaments;
	}

}
